/*
 * @author Chris
 * @since 2023/2/4 19:18
 *
 * @brief    The project will ...
 *
 * @note     ...
 *
 * @warning  Do not to ...
 *
 * Change Logs:
 *   Date           Author       Notes
 *   2023/2/4     Chris        the first version
 */

#include "8052.h"

#define DS1302_CE P1_7
#define DS1302_CK P3_5
#define DS1302_IO P3_4

__sbit flag200ms = 0;
unsigned char T0RH = 0;
unsigned char T0RL = 0;

void ConfigTimer0(unsigned char ms);

void InitDS1302();

unsigned char DS1302SingleRead(unsigned char reg);

void DS1302SingleWrite(unsigned char reg, unsigned char dat);

extern void InitLcd1602();

extern void Lcd1602Show(unsigned char x, unsigned char y, unsigned char *buf, unsigned char len);

int main() {

    EA = 1;
    ConfigTimer0(1);
    InitLcd1602();
    InitDS1302();

    unsigned char secBak = 0x61;
    while (1) {
        if (flag200ms) {
            flag200ms = 0;

            unsigned char time[8];
            for (int i = 0; i < 7; ++i) {
                time[i] = DS1302SingleRead(i);
            }

            if (secBak != time[0]) {
                unsigned char timeBuf[12];
                // 日期
                timeBuf[0] = '2';
                timeBuf[1] = '0';
                timeBuf[2] = (time[6] >> 4) + '0';
                timeBuf[3] = (time[6] & 0x0F) + '0';
                timeBuf[4] = '-';

                timeBuf[5] = (time[4] >> 4) + '0';
                timeBuf[6] = (time[4] & 0x0F) + '0';
                timeBuf[7] = '-';

                timeBuf[8] = (time[3] >> 4) + '0';
                timeBuf[9] = (time[3] & 0x0F) + '0';
                timeBuf[10] = ' ';
                Lcd1602Show(0, 0, timeBuf, 11);

                // 星期
                timeBuf[0] = (time[5] & 0x0F) + '0';
                Lcd1602Show(11, 0, "week", 4);
                Lcd1602Show(15, 0, timeBuf, 1);

                // 时间
                timeBuf[0] = (time[2] >> 4) + '0';
                timeBuf[1] = (time[2] & 0x0F) + '0';
                timeBuf[2] = ':';
                timeBuf[3] = (time[1] >> 4) + '0';
                timeBuf[4] = (time[1] & 0x0F) + '0';
                timeBuf[5] = ':';
                timeBuf[6] = (time[0] >> 4) + '0';
                timeBuf[7] = (time[0] & 0x0F) + '0';
                Lcd1602Show(4, 1, timeBuf, 8);

                secBak = time[0];
            }

        }
    }
}

void DS1302ByteWrite(unsigned char dat) {
    for (unsigned char mask = 0x01; mask != 0; mask <<= 1) {
        DS1302_IO = (dat & mask) == 0 ? 0 : 1;
        DS1302_CK = 1;
        DS1302_CK = 0;
    }
    DS1302_IO = 1;
}

unsigned char DS1302ByteRead() {
    unsigned char dat = 0x00;
    for (unsigned char mask = 0x01; mask != 0; mask <<= 1) {
        dat = dat | (DS1302_IO == 0 ? 0 : mask);
        DS1302_CK = 1;
        DS1302_CK = 0;
    }
    return dat;
}

void DS1302SingleWrite(unsigned char reg, unsigned char dat) {
    DS1302_CE = 1;
    DS1302ByteWrite(0x80 | (reg << 1));
    DS1302ByteWrite(dat);
    DS1302_CE = 0;
}

unsigned char DS1302SingleRead(unsigned char reg) {
    DS1302_CE = 1;
    DS1302ByteWrite(0x81 | (reg << 1));
    unsigned char dat = DS1302ByteRead();
    DS1302_CE = 0;
    return dat;
}

void InitDS1302() {
    unsigned char register0 = DS1302SingleRead(0);
    if ((register0 & 0x80) == 0) {
        // 掉电后继续工作
        return;
    }
    unsigned char __code initTime[] = {0x15, 0x20, 0x17, 0x04, 0x02, 0x01, 0x23};

    DS1302_CE = 0;
    DS1302_CK = 0;

    DS1302SingleWrite(7, 0x00);

    for (int i = 0; i < sizeof(initTime); ++i) {
        DS1302SingleWrite(i, initTime[i]);
    }

}

void ConfigTimer0(unsigned char ms) {
    TMOD = (TMOD & 0xF0) | 0x01;
    unsigned char tmp = 65536 - 11059200 / 12 * ms / 1000 + 12;
    T0RH = tmp >> 8;
    T0RL = tmp & 0xFF;

    TH0 = T0RH;
    TL0 = T0RL;

    ET0 = 1;
    TR0 = 1;
}

/**
 * 定时器 T0 中断服务函数
 */
void InterruptTimer0() __interrupt(1) {
    TH0 = T0RH;
    TL0 = T0RL;

    static unsigned char cnt = 0;
    if (cnt++ >= 200) {
        cnt = 0;
        flag200ms = 1;
    }
}